﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Migracion.Data;
using Migracion.Data.PeOnline;
using System.Diagnostics;
using System.Xml.Linq;
using System.IO;
using Migracion.Data.Tagging;
using System.Text.RegularExpressions;
using System.Web;
using Migracion.Process.voz;
using Migracion.Data.ArbolVoces;
using System.Data.SqlClient;
using System.Data.Common;
using System.Configuration;

namespace Migracion.Process
{
    public class JurisprudenciaProc : BaseProcess
    {
        public const string StrEstadoConTexto = "Con texto";
        public const string StrEstadoSinTexto = "Sin texto";
        public const string StrNotaInterna = "ORIGEN_ABELEDO_PERROT";
        public const string StrPais = "Argentina AP";      

        public string OutputPath { get; set; }

        public bool ProcesarTextoCompleto { get; set; }

        public string AbeledoId { get; set; }

        public string SQLText { get; set; }

        private bool cancelaProceso = false;
        private object cancelaProcesoLock = false;

        public bool CancelarProceso
        {
            get
            {
                lock (cancelaProcesoLock)
                {
                    return cancelaProceso;
                }
            }
            set
            {
                lock (cancelaProcesoLock)
                {
                    cancelaProceso = value;
                }
            }
        }

        public void DoProcess()
        {
            if (ProcesarTextoCompleto)
            {
                DoProcessFallosTC();
            }
            else
            {
                DoProcessSoloSumarios();
            }
        }

        protected void DoProcessFallosTC()
        {
            int imax = 0;

            try
            {
                watch.Start();
                LogStatusMessage("Inicio de Generación de XMLs de Jurisprudencia Fallos TC", MigracionLogStatus.Information);
                InicializarManagers();
                List<int> Ids = new List<int>();
                using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
                {
                    // Leer los datos
                    Ids = ObtenerIdsAProcesarFallosTC(ctxPeOnline);

                    if (Ids.Count == 0)
                    {
                        LogStatusMessage("No se encontraron fallos para procesar", MigracionLogStatus.Information);
                    }
                }

                // Por cada dato,
                imax = Ids.Count;
                bool cancelar = false;
                cantidadDeFallosOk = 0;
                for (int i = 0; i < imax && !cancelar; i++)
                {
                    int idFallo = Ids[i];

                    currentId = idFallo.ToString();
                    if (CancelarProceso)
                    {
                        cancelar = true;
                    }
                    else
                    {
                        if (i % 5000 == 0)
                        {
                            GC.Collect();
                        }

                        // generar el XML
                        try
                        {
                            GenerarXMLFalloTextoCompleto(idFallo);
                            cantidadDeFallosOk++;
                            LogStatusMessage("Fallo Procesado: " + idFallo.ToString(), MigracionLogStatus.Information);
                        }
                        catch (Exception exIndividual)
                        {
                            LogStatusMessage("Error excepción en el documento " + GetExceptionMessage(exIndividual) + GetExceptionStackTrace(exIndividual), MigracionLogStatus.Error);
                        }

                        ProgressStatus(i + 1, imax);
                    }
                }
            }
            catch (Exception ex)
            {
                LogStatusMessage("Ha ocurrido una excepción: " + GetExceptionMessage(ex) + GetExceptionStackTrace(ex), MigracionLogStatus.Error);
            }
            finally
            {
                if (CancelarProceso)
                {
                    LogStatusMessage("Proceso Cancelado", MigracionLogStatus.Information);
                }
                else
                {
                    LogStatusMessage(string.Format("Proceso Finalizado, procesados ok {0} de {1}", cantidadDeFallosOk, imax), MigracionLogStatus.Information);
                }

                watch.Stop();
            }
        }

        protected void DoProcessSoloSumarios()
        {
            int imax = 0;
            int cantidadDeFallosOk = 0;
            try
            {
                watch.Start();
                LogStatusMessage("Inicio de Generación de XMLs de Jurisprudencia Solo Sumarios", MigracionLogStatus.Information);
                InicializarManagers();
                List<int> Ids = new List<int>();
                using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
                {
                    // pone en cero los grupos procesados de jurisprudencia para sumarios
                    //ctxPeOnline.ResetearGruposProcesados();

                    // Leer los datos
                    Ids = ObtenerIdsAProcesarSumarios(ctxPeOnline);
                }

                if (Ids.Count == 0)
                {
                    LogStatusMessage("No se encontraron sumarios para procesar", MigracionLogStatus.Information);
                }

                // Por cada dato,
                imax = Ids.Count;
                bool cancelar = false;
                for (int i = 0; i < imax && !cancelar; i++)
                {
                    int idSumario = Ids[i];
                    this.currentId = idSumario.ToString();
                    if (CancelarProceso)
                    {
                        cancelar = true;
                    }
                    else
                    {
                        if (i % 5000 == 0)
                        {
                            GC.Collect();
                        }

                        // generar el XML
                        try
                        {
                            GenerarXMLSumarioSinTexto(idSumario);
                            cantidadDeFallosOk++;
                            LogStatusMessage("Sumario Procesado: " + idSumario.ToString(), MigracionLogStatus.Information);
                        }
                        catch (Exception exIndividual)
                        {
                            LogStatusMessage("Error excepción en el documento " + GetExceptionMessage(exIndividual) + GetExceptionStackTrace(exIndividual), MigracionLogStatus.Error);
                        }

                        ProgressStatus(i + 1, imax);
                    }
                }

            }
            catch (Exception ex)
            {
                LogStatusMessage("Ha ocurrido una excepción: " + GetExceptionMessage(ex) + GetExceptionStackTrace(ex), MigracionLogStatus.Error);
            }
            finally
            {
                if (CancelarProceso)
                {
                    LogStatusMessage("Proceso Cancelado", MigracionLogStatus.Information);
                }
                else
                {
                    LogStatusMessage(string.Format("Proceso Finalizado, procesados ok {0} de {1}", cantidadDeFallosOk, imax), MigracionLogStatus.Information);
                }

                watch.Stop();
            }
        }

        private List<int> ObtenerIdsAProcesarFallosTC(PE_ONLINE_PRODUCCIONEntities ctxPeOnline)
        {
            List<int> ids = new List<int>();
            if (!String.IsNullOrEmpty(SQLText))
            {
                string constr = ConfigurationManager.ConnectionStrings["PE_ONLINE_PRODUCCIONSelect"].ConnectionString;
                using (DbConnection connection = new SqlConnection(constr))
                {
                    try
                    {
                        connection.Open();
                        DbCommand command = connection.CreateCommand();
                        command.CommandText = this.SQLText;
                        command.CommandType = System.Data.CommandType.Text;

                        using (DbDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                ids.Add(reader.GetInt32(0));
                            }

                            reader.Close();
                        }
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
            else
            {
                if (!String.IsNullOrEmpty(AbeledoId))
                {
                    int? idFallo = (from jf in ctxPeOnline.tJurisFallo
                                    join il in ctxPeOnline.tIdentLexis on jf.IdIdentLexis equals il.Id
                                    where il.IdentLexis == AbeledoId
                                    && jf.IdIdentLexis.HasValue
                                    select jf.IdJJ).SingleOrDefault();

                    if (idFallo.HasValue && idFallo.Value != default(int))
                    {
                        ids.Add(idFallo.Value);
                    }
                }
                else
                {
                    ids.AddRange((from jf in ctxPeOnline.tJurisFallo
                                  join il in ctxPeOnline.tIdentLexis on jf.IdIdentLexis equals il.Id
                                  where jf.IdIdentLexis.HasValue
                                  select jf.IdJJ).ToList());
                }
            }

            return ids;
        }

        /// <summary>
        /// Esto procesa solo sumarios
        /// </summary>
        /// <param name="ctxPeOnline"></param>
        /// <returns></returns>
        private List<int> ObtenerIdsAProcesarSumarios(PE_ONLINE_PRODUCCIONEntities ctxPeOnline)
        {
            List<int> ids = new List<int>();
            if (!String.IsNullOrEmpty(SQLText))
            {
                string constr = ConfigurationManager.ConnectionStrings["PE_ONLINE_PRODUCCIONSelect"].ConnectionString;
                using (DbConnection connection = new SqlConnection(constr))
                {
                    try
                    {
                        connection.Open();
                        DbCommand command = connection.CreateCommand();
                        command.CommandText = this.SQLText;
                        command.CommandType = System.Data.CommandType.Text;

                        using (DbDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                ids.Add(reader.GetInt32(0));
                            }

                            reader.Close();
                        }
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
            else
            {
                if (!String.IsNullOrEmpty(AbeledoId))
                {
                    int? idSumario = (from jf in ctxPeOnline.tJurisSumario
                                      join il in ctxPeOnline.tIdentLexis on jf.IdIdentLexis equals il.Id
                                      where il.IdentLexis == AbeledoId
                                      && jf.IdIdentLexis.HasValue
                                      select jf.IdJJSumario).SingleOrDefault();

                    if (idSumario.HasValue && idSumario.Value != default(int))
                    {
                        ids.Add(idSumario.Value);
                    }
                }
                else
                {
                    ids.AddRange((from jf in ctxPeOnline.tJurisSumario
                                  join il in ctxPeOnline.tIdentLexis on jf.IdIdentLexis equals il.Id
                                  where jf.IdIdentLexis.HasValue
                                  select jf.IdJJSumario).ToList());
                }
            }

            return ids;
        }

        private void GenerarXMLFalloTextoCompleto(int idFallo)
        {
            string nombreDocumento = idFallo.ToString() + ".xml";
            MigraDocLog migraDocLogEntry = new MigraDocLog();
            migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
            migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tJurisFallo;
            migraDocLogEntry.Excepcion = false;
            migraDocLogEntry.Mensaje = string.Empty;

            using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
            {
                try
                {
                    XDocument falloDocument = new XDocument();

                    tJurisFallo jurisFallo = ctxPeOnline.tJurisFallo.Where(f => f.IdJJ == idFallo).SingleOrDefault();
                    if (jurisFallo == null)
                    {
                        LogStatusMessage("No se encontró el fallo", MigracionLogStatus.Information);
                        return;
                    }

                    XElement documentoElement = new XElement("documento");
                    falloDocument.Add(documentoElement);
                    XElement metaDocumentoElement = new XElement("meta-documento");
                    documentoElement.Add(metaDocumentoElement);
                    XElement falloGuidElement = new XElement("guid");
                    metaDocumentoElement.Add(falloGuidElement);
                    Guid falloGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tJurisFallo, idFallo);
                    falloGuidElement.Value = falloGuid.ToString();
                    migraDocLogEntry.GuidSae = falloGuid;
                    migraDocLogEntry.ApId = idFallo.ToString();
                    metaDocumentoElement.Add(new XElement("iddoc"));
                    XElement citaElement = new XElement("cita");
                    metaDocumentoElement.Add(citaElement);
                    citaElement.Value = jurisFallo.tIdentLexis.IdentLexis;
                    XElement novusElement = new XElement("novus", new XElement("id"), new XElement("accion", IdTranslationManager.GetDocumentoEstadoEnviarNovus(jurisFallo.IdDocumentoEstado)), new XElement("fecha-de-modificacion", "T"));
                    metaDocumentoElement.Add(novusElement);

                    XElement fechaDeCarga = new XElement("fecha-carga");
                    metaDocumentoElement.Add(fechaDeCarga);
                    fechaDeCarga.Value = jurisFallo.FechaAlta.ToStringSAE();

                    metaDocumentoElement.Add(new XElement("fecha-ultima-modificacion", DateTime.Now.ToStringSAE()));
                    metaDocumentoElement.Add(new XElement("estado-texto", StrEstadoConTexto));

                    XElement tribunalElement = new XElement("tribunal");
                    metaDocumentoElement.Add(tribunalElement);
                    tJurisFalloCaratula jurisFalloCaratula = jurisFallo.tJurisFalloCaratula.OrderBy(f => f.IdCaratula).First();

                    tTribunal ttribunal = null;
                    // TODO: el ID es un entero
                    if (jurisFalloCaratula.IdTribunal.HasValue)
                    {
                        ttribunal = ctxPeOnline.tTribunal.Where(t => t.id_tribunal == jurisFalloCaratula.IdTribunal.Value).Single();

                        string idTribunalCombinado = ttribunal.id_tribunal.ToString();
                        if (jurisFalloCaratula.IdSala.HasValue)
                        {
                            var sala = ctxPeOnline.tSala.Where(s => s.id_sala == jurisFalloCaratula.IdSala.Value).SingleOrDefault();
                            if (sala != null)
                            {
                                idTribunalCombinado += "S" + HtmlDecode(sala.nombre);
                            }
                        }

                        tribunalElement.Add(new XAttribute("descripcion", HtmlDecode(ttribunal.nombre)), new XAttribute("idoriginal", idTribunalCombinado));

                        tribunalElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTribunal, idTribunalCombinado);
                    }

                    metaDocumentoElement.Add(new XElement("nota-interna", StrNotaInterna));                    

                    //<nro-sentencia nro-sentencia="" nro-expediente="">
                    string nroSentencia = jurisFallo.NroSentencia ?? string.Empty;
                    string nroExpediente = jurisFallo.NroExpediente ?? string.Empty;
                    metaDocumentoElement.Add(new XElement("nro-sentencia", nroSentencia));
                    metaDocumentoElement.Add(new XElement("nro-expediente", nroExpediente));

                    metaDocumentoElement.Add(new XElement("fecha-sentencia", jurisFalloCaratula.Fecha.ToStringSAE()));

                    using (TaggingEntities ctxTagging = new TaggingEntities())
                    {
                        tFallos falloTagging = ctxTagging.tFallos.Where(t => t.IdDocumento == jurisFallo.tIdentLexis.IdentLexis).SingleOrDefault();

                        if (falloTagging != null)
                        {
                            metaDocumentoElement.Add(new XElement("parte-actora"));
                            metaDocumentoElement.Add(new XElement("parte-actora-pub", falloTagging.Actor));
                            metaDocumentoElement.Add(new XElement("parte-demandada"));
                            metaDocumentoElement.Add(new XElement("parte-demandada-pub", falloTagging.Demandado));
                            metaDocumentoElement.Add(new XElement("partes", HtmlDecode(jurisFalloCaratula.Partes)));
                            metaDocumentoElement.Add(new XElement("objeto", HtmlDecode(falloTagging.Objeto)));
                        }
                        else
                        {
                            metaDocumentoElement.Add(new XElement("parte-actora"));
                            metaDocumentoElement.Add(new XElement("parte-actora-pub"));
                            metaDocumentoElement.Add(new XElement("parte-demandada"));
                            metaDocumentoElement.Add(new XElement("parte-demandada-pub"));
                            metaDocumentoElement.Add(new XElement("partes", HtmlDecode(jurisFalloCaratula.Partes)));
                            metaDocumentoElement.Add(new XElement("objeto"));
                        }
                    }

                    tSentencia tsentencia = ctxPeOnline.tSentencia.Where(s => s.IdSentencia == jurisFallo.IdTipoSentencia).SingleOrDefault();
                    XElement tipoSentenciaElement = new XElement("tipo-sentencia");
                    metaDocumentoElement.Add(tipoSentenciaElement);
                    if (tsentencia != null)
                    {
                        tipoSentenciaElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tSentencia, HtmlDecode(tsentencia.Descripcion)).ToString();
                    }

                    // TODO: revisar con regular expressión las citas : Cambiar las citas diferenciando entre fallos de corte y apariciones
                    XElement citaFalloCorteElement = new XElement("cita-fallo-corte");
                    metaDocumentoElement.Add(citaFalloCorteElement);

                    XElement citaDictamenProcTesoroElement = new XElement("cita-dictamen-proc-tesoro");
                    metaDocumentoElement.Add(citaDictamenProcTesoroElement);

                    XElement nroClasificacionElement = new XElement("nro-clasificacion");
                    metaDocumentoElement.Add(nroClasificacionElement);

                    using (TaggingEntities ctxTagging = new TaggingEntities())
                    {
                        List<int?> clasificacionesDelFallo = (from doc in ctxTagging.tDocumentos
                                                              join paq in ctxTagging.tPaquetes on doc.IdPaquete equals paq.IdPaquete
                                                              where doc.IdDocumento == jurisFallo.tIdentLexis.IdentLexis
                                                              select paq.Clasificacion).ToList();

                        if (clasificacionesDelFallo.Count > 0)
                        {
                            if (clasificacionesDelFallo[0].HasValue)
                            {
                                nroClasificacionElement.Value = clasificacionesDelFallo[0].Value.ToString();
                            }
                        }
                    }

                    XElement aparicionesElement = new XElement("apariciones");

                    //Regex regexCitaAFalloCorte = new Regex("");
                    // Las citas en SAE pueden ser apariciones o fallos de corte
                    foreach (var fallocita in jurisFalloCaratula.tCita)
                    {
                        // Fallos de corte
                        // Fallos 320:1254
                        if (citasAP.Where(cap => fallocita.Nombre.StartsWith(cap.Starts) && cap.TipoDeCita == CitaAp.fallocorte).Count() > 0)
                        {
                            citaFalloCorteElement.Add(new XElement("cita", HtmlDecode(fallocita.Nombre)));
                        }
                        else if (citasAP.Where(cap => fallocita.Nombre.StartsWith(cap.Starts) && cap.TipoDeCita == CitaAp.dictamen).Count() > 0)
                        {
                            citaDictamenProcTesoroElement.Add(new XElement("cita", HtmlDecode(fallocita.Nombre)));
                        }
                        else
                        {
                            List<string> publicaciones = fallocita.Nombre.Split(';').ToList();
                            foreach (string publi in publicaciones)
                            {
                                string publicacion = publi.Trim();                              
                                CitaAp citaAp;
                                if (publicacion.StartsWith("RDAmb"))
                                {
                                    citaAp = citasAP.Where(c => "RDAmb" == c.Starts).SingleOrDefault();
                                }
                                else if (publicacion.StartsWith("RDA"))
                                {
                                    citaAp = citasAP.Where(c => "RDA" == c.Starts).SingleOrDefault();
                                }
                                else
                                {
                                    citaAp = citasAP.Where(c => publicacion.StartsWith(c.Starts) && c.TipoDeCita == CitaAp.aparicion).SingleOrDefault();
                                }                               

                                if (citaAp != null)
                                {
                                    //string productoPublicacion = publicacion.Substring(0, publicacion.IndexOf(' '));
                                    XElement aparicionElement = new XElement("aparicion");
                                    aparicionesElement.Add(aparicionElement);
                                    aparicionElement.Add(new XElement("coleccion", this.IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tPublicacionFallo, citaAp.Starts)));
                                    aparicionElement.Add(new XElement("componente")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("pag")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("fecha")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("nro-fallo")); // TODO: completar, ver
                                    aparicionElement.Add(new XElement("desc", HtmlDecode(publicacion))); // TODO: completar, ver
                                }
                            }
                        }
                    }

                    XElement citasElement = new XElement("citas");
                    metaDocumentoElement.Add(citasElement);

                    AgregarAnalisisDeCita(citasElement, jurisFalloCaratula.tCita);

                    // No informar
                    metaDocumentoElement.Add(new XElement("nro-plenario"));
                    metaDocumentoElement.Add(new XElement("rol"));
                    XElement tituloElement = new XElement("titulo");
                    metaDocumentoElement.Add(tituloElement);

                    //XElement tipoDeFallo = new XElement("tipo-fallo-AP");
                    //metaDocumentoElement.Add(tipoDeFallo);
                    //using (TaggingEntities ctxTagging = new TaggingEntities())
                    //{

                    //}

                    // Ministros
                    XElement ministrosElement = new XElement("ministros");
                    metaDocumentoElement.Add(ministrosElement);
                    foreach (var jurisMinistro in jurisFallo.tJurisFalloMinistro)
                    {
                        tMinistro ministro = ctxPeOnline.tMinistro.Where(m => m.IdMinistro == jurisMinistro.IdMinistro).Single();
                        XElement ministroElement = new XElement("ministro");

                        if (ministro.Nombre == "SIN DISIDENCIA" || jurisMinistro.TipoVoto == 6)
                        {
                        }
                        else
                        {

                            ministroElement.Add(new XAttribute("nombre", HtmlDecode(ministro.Nombre)));
                            ministroElement.Add(new XAttribute("orden", jurisMinistro.Orden));

                            ministroElement.Add(new XAttribute("tipovoto", IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoVoto, jurisMinistro.TipoVoto)));
                            ministroElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tMinistro, ministro.IdMinistro).ToString();
                            ministrosElement.Add(ministroElement);
                        }
                    }

                    metaDocumentoElement.Add(new XElement("redactores")); // Chile no inftormar
                    metaDocumentoElement.Add(new XElement("abogados-integrantes"));

                    metaDocumentoElement.Add(aparicionesElement);

                    //metaDocumentoElement.Add(new XElement("publicacion"));
                    metaDocumentoElement.Add(new XElement("asignaciones"));

                    XElement collectionsSetElement = new XElement("collection-sets");
                    metaDocumentoElement.Add(collectionsSetElement);

                    // Se agregan los productos
                    foreach (tProducto tproducto in jurisFallo.tProducto1)
                    {
                        List<Guid> guidForProductoList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tProducto, tproducto.id_producto);

                        foreach (Guid guidForProducto in guidForProductoList)
                        {
                            XElement collectionSetElement = new XElement("collection-set");
                            collectionsSetElement.Add(collectionSetElement);
                            collectionSetElement.Value = guidForProducto.ToString();
                        }
                    }

                    metaDocumentoElement.Add(new XElement("productos-digitales"));

                    // TODO: solo las voces, no los terminos libres
                    XElement vocesIndizacionElement = new XElement("voces-indizacion");
                    metaDocumentoElement.Add(vocesIndizacionElement);

                    XElement vocesElement = new XElement("voces");
                    XElement vozPrincipalElement = new XElement("voz-principal");
                    vocesElement.Add(vozPrincipalElement);
                    XElement subVocesElement = new XElement("sub-voces");
                    vocesElement.Add(subVocesElement);

                    List<MigraVoz> vocesFiltradasPorArbolDeVoces = (from jft in jurisFallo.tJurisFalloTaxonomia
                                                                    orderby jft.nivel, jft.Nro
                                                                    select new MigraVoz
                                                                    {
                                                                        Nombre = HtmlDecode(jft.tTaxonomia.Nombre),
                                                                        IdTaxonomia = jft.IdTaxonomia,
                                                                        Nivel = jft.nivel,
                                                                        Numero = jft.Nro
                                                                    }).ToList();

                    vocesFiltradasPorArbolDeVoces = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVoces);

                    StringBuilder tituloBuilder = new StringBuilder();
                    string separador = string.Empty;
                    foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                    {
                        XElement vozElement;
                        if (migraVoz.EsVozDelArbolDeVoces) //Se informan las voces que son parte del árbol como voces, en <voces-indizacion> del fallo.
                        {
                            vozElement = new XElement("voz-indizacion");
                            vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                            vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                            vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                            vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                            vozElement.Value = migraVoz.Nombre;
                            vocesIndizacionElement.Add(vozElement);

                            vozElement = new XElement("voz");
                            vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                            vozElement.Value = migraVoz.Nombre;
                            vozPrincipalElement.Add(vozElement);
                        }
                        else
                        {
                            tituloBuilder.Append(separador);
                            separador = " " + SeparadorDeVocesChar + " ";
                            tituloBuilder.Append(migraVoz.Nombre);
                        }

                        vozElement = new XElement("voz");
                        vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                        vozElement.Value = migraVoz.Nombre;
                        subVocesElement.Add(vozElement);
                    }

                    tituloElement.Value = tituloBuilder.ToString();

                    metaDocumentoElement.Add(vocesElement);
                    metaDocumentoElement.Add(new XElement("citas-legales"));
                    metaDocumentoElement.Add(new XElement("hechos"));
                    metaDocumentoElement.Add(new XElement("comentario-dj"));
                    metaDocumentoElement.Add(new XElement("pais", StrPais));

                    metaDocumentoElement.Add(new XElement("informacion-complementaria"));
                    metaDocumentoElement.Add(new XElement("honorarios-del-abogado"));
                    metaDocumentoElement.Add(new XElement("cuota-alimentaria"));

                    List<tJurisSumarioCaratula> tJurisSumarioCaratulaList = ctxPeOnline.tJurisSumarioCaratula.Where(jsc => jsc.ArchTCompleto == jurisFallo.ArchFisico && jsc.tJurisSumario.IdIdentLexis.HasValue).ToList();

                    XElement integraciontribunalElement = new XElement("integracion-tribunal");
                    metaDocumentoElement.Add(integraciontribunalElement);
                    bool sinDisidencia = false;

                    if (jurisFallo.tJurisFalloMinistro.Count > 0)
                    {
                        foreach (var jurisMinistro in jurisFallo.tJurisFalloMinistro)
                        {
                            tMinistro magistrado = ctxPeOnline.tMinistro.Where(m => m.IdMinistro == jurisMinistro.IdMinistro).Single();
                            if (magistrado.Nombre == "SIN DISIDENCIA" || jurisMinistro.TipoVoto == 6)
                            {
                                sinDisidencia = true;
                            }
                            else
                            {
                                XElement magistradoElement = new XElement("magistrado");
                                magistradoElement.Add(new XAttribute("nombre", magistrado.Nombre));
                                magistradoElement.Add(new XAttribute("orden", jurisMinistro.Orden));
                                magistradoElement.Add(new XAttribute("tipovoto", IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoVoto, jurisMinistro.TipoVoto)));
                                magistradoElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tMinistro, magistrado.IdMinistro).ToString();
                                integraciontribunalElement.Add(magistradoElement);
                            }
                        }
                    }
                    else
                    {
                        // Intento con algún sumario para obtener los ministros
                        if (tJurisSumarioCaratulaList.Count > 0)
                        {
                            tJurisSumarioCaratula sumarioCaratula = tJurisSumarioCaratulaList[0];
                            foreach (var jurisMinistro in sumarioCaratula.tJurisSumario.tJurisSumarioCaratulaMinistro)
                            {
                                tMinistro magistrado = ctxPeOnline.tMinistro.Where(m => m.IdMinistro == jurisMinistro.IdMinistro).Single();
                                if (magistrado.Nombre == "SIN DISIDENCIA" || jurisMinistro.TipoVoto == 6)
                                {
                                    sinDisidencia = true;
                                }
                                else
                                {
                                    XElement magistradoElement = new XElement("magistrado");
                                    magistradoElement.Add(new XAttribute("nombre", magistrado.Nombre));
                                    magistradoElement.Add(new XAttribute("orden", jurisMinistro.Orden));
                                    magistradoElement.Add(new XAttribute("tipovoto", IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoVoto, jurisMinistro.TipoVoto)));
                                    magistradoElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tMinistro, magistrado.IdMinistro).ToString();
                                    integraciontribunalElement.Add(magistradoElement);
                                }
                            }
                        }
                    }

                    metaDocumentoElement.Add(new XElement("sin-disidencia", sinDisidencia ? "SI" : "NO"));

                    // TODO: buscar la doctrina relacionada (falta definir formato, nota a fallo)
                    XElement documentosRelacionadosElement = new XElement("documentos-relacionados");
                    metaDocumentoElement.Add(documentosRelacionadosElement);
                    CargarDocumentosRelacionadosParaJurisprudencia(ctxPeOnline, documentosRelacionadosElement, jurisFallo);

                    XElement materiasElement = new XElement("materias");
                    metaDocumentoElement.Add(materiasElement);

                    var tjurisFalloMaterias = ctxPeOnline.tJurisFalloMateria.Where(tjfm => tjfm.idJJ == jurisFallo.IdJJ).ToList();
                    string separadorNuflo = string.Empty;
                    foreach (var tjurisFalloMateria in tjurisFalloMaterias)
                    {
                        tMateria materia = ctxPeOnline.tMateria.Where(m => m.id_Materia == tjurisFalloMateria.id_Materia).Single();
                        List<Guid> guidSaeMateriaList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tMateria, materia.id_Materia);//GetGuidListIdForApEntity
                        foreach (Guid guidSaeMateria in guidSaeMateriaList)
                        {
                            XElement materiaElement = new XElement("materia");
                            materiaElement.Add(new XAttribute("identificador", materia.Identificador));
                            materiaElement.Add(new XAttribute("nombre", HtmlDecode(materia.Descripcion)));
                            materiaElement.Value = guidSaeMateria.ToString();
                            materiasElement.Add(materiaElement);
                        }
                    }

                    // Chile, no informar
                    metaDocumentoElement.Add(new XElement("estado-procesal"));
                    metaDocumentoElement.Add(new XElement("tipo-recurso"));
                    metaDocumentoElement.Add(new XElement("tipo-resultado"));


                    XElement contenidoDocumentoElement = new XElement("cont-documento");
                    documentoElement.Add(contenidoDocumentoElement);


                    XElement textoSentenciaElement = new XElement("texto-sentencia");
                    contenidoDocumentoElement.Add(textoSentenciaElement);

                    textoSentenciaElement.Add(new XCData(ProcesarCuerpo(ctxPeOnline, falloGuid, jurisFallo.IdJJ, jurisFallo.Cuerpo)));

                    XElement sumariosElement = new XElement("sumarios");
                    contenidoDocumentoElement.Add(sumariosElement);


                    int i = 0;
                    foreach (tJurisSumarioCaratula tjurissumarioCaratula in tJurisSumarioCaratulaList)
                    {
                        ProcesarSumarioParaDocumento(ctxPeOnline, nombreDocumento, sumariosElement, i, tjurissumarioCaratula);
                        i++;
                    }

                    string path = Path.Combine(this.OutputPath, "FallosTC");
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    falloDocument.Save(Path.Combine(path, nombreDocumento));
                }
                catch (Exception ex)
                {
                    migraDocLogEntry.Excepcion = true;
                    string message = GetExceptionMessage(ex);
                    string stack = GetExceptionStackTrace(ex);
                    migraDocLogEntry.Mensaje = message + stack;
                    throw;
                }
                finally
                {
                    ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                    ctxPeOnline.SaveChanges();
                }
            }
        }

        public static List<CitaAp> citasAP = new List<CitaAp>()
        {
            new CitaAp(){ Starts = "BA", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "Fallos", TipoDeCita = CitaAp.fallocorte },
            new CitaAp(){ Starts = "CHU", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "SE", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "MZA", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "NQ", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "JO", TipoDeCita = CitaAp.baseoficial },
            new CitaAp(){ Starts = "Dict", TipoDeCita = CitaAp.dictamen },
      
            new CitaAp(){ Starts = "JA", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDLSS", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDCO", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "LNL", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "LNBA", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "LNC", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "APBA", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDFI", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "SJA", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "APC", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDF ", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "as", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "TO", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDAmb", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "RDA", TipoDeCita = CitaAp.aparicion },                       
            new CitaAp(){ Starts = "RDP", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "AP%%BA", TipoDeCita = CitaAp.aparicion },
            new CitaAp(){ Starts = "NN", TipoDeCita = CitaAp.aparicion }
        };

        public static void AgregarAnalisisDeCita(XElement citasElement, System.Data.Objects.DataClasses.EntityCollection<tCita> entityCollection)
        {
            foreach (var cita in entityCollection)
            {
                List<string> publicaciones = cita.Nombre.Split(';').ToList();
                foreach (var pub in publicaciones)
                {
                    string publicacion = pub.Trim();
                    CitaAp citaAp;
                    if (publicacion.StartsWith("RDAmb"))
                    {
                        citaAp = citasAP.Where(c => "RDAmb" == c.Starts).SingleOrDefault();
                    }
                    else if(publicacion.StartsWith("RDA"))
                    {
                        citaAp = citasAP.Where(c => "RDA" == c.Starts).SingleOrDefault();
                    }
                    else
                    {
                        citaAp = citasAP.Where(c => publicacion.StartsWith(c.Starts)).SingleOrDefault();
                    }
                   
                    if (citaAp != null)
                    {
                        XElement citaElement = new XElement("cita", new XAttribute("tipo", citaAp.TipoDeCita));
                        citaElement.Value = HtmlDecode(publicacion);
                        citasElement.Add(citaElement);
                    }
                }
            }
        }

        private void CargarDocumentosRelacionadosParaJurisprudencia(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, XElement documentosRelacionadosElement, tJurisFallo jurisFallo)
        {
            if (!String.IsNullOrEmpty(jurisFallo.Comentario))
            {
                string comentario = HtmlDecode(jurisFallo.Comentario);
                comentario = "<root>" + comentario + "</root>";
                comentario = EscapearTexto(comentario);
                List<XElement> parrafosEnElComentario;
                using (StringReader strReader = new StringReader(comentario))
                {
                    XDocument xComentarioFallo = XDocument.Load(strReader);
                    parrafosEnElComentario = (from node in xComentarioFallo.Descendants()
                                              where node.Name == "Parrafo"
                                              select node).ToList();


                    foreach (var parrafoElement in parrafosEnElComentario)
                    {
                        if (!parrafoElement.Value.StartsWith("Comentario") && !String.IsNullOrEmpty(parrafoElement.Value))
                        {
                            string textoNota = HtmlDecode(parrafoElement.Value);

                            var citaElement = (from node in parrafoElement.Descendants()
                                               where node.Name == "Cita"
                                               && node.Attribute("tipo").Value == "jj_anotada"
                                               select node).SingleOrDefault();

                            if (citaElement == null)
                            {
                                citaElement = (from node in parrafoElement.Descendants()
                                               where node.Name == "Cita"
                                               && node.Attribute("tipo").Value == "lexis"
                                               select node).SingleOrDefault();
                            }

                            if (citaElement != null)
                            {
                                // Obtengo el documento de doctrina
                                string archivofisico = citaElement.Attribute("ref").Value;
                                var doctrinaRelacionada = ctxPeOnline.tDoctrinaSumario.Where(ds => ds.ArchFisico == archivofisico && ds.IdIdentLexis.HasValue).SingleOrDefault();
                                if (doctrinaRelacionada != null)
                                {
                                    XElement documentoElement = new XElement("documento");
                                    XElement guidRelacionadoElement = new XElement("guid");
                                    guidRelacionadoElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tDoctrinaSumario, doctrinaRelacionada.IdDDSumario).ToString();
                                    documentoElement.Add(guidRelacionadoElement);
                                    documentoElement.Add(new XElement("subtipo", new XAttribute("sigla", "NF")));
                                    documentoElement.Add(new XElement("texto-ref", textoNota));
                                    documentosRelacionadosElement.Add(documentoElement);
                                }
                            }
                        }
                    }
                }

                //string textoStr = xCuerpoFallo.ToString();
                //textoStr = textoStr.Remove(0, 6); 
                //if (textoStr[0] == '\r' && textoStr[1] == '\n')
                //{
                //    textoStr = textoStr.Remove(0, 2);
                //}

                //textoStr = textoStr.Remove(textoStr.Length - 7, 7);
                //return textoStr;
            }
        }

        /// <summary>
        /// Carga si pertenecen al arbol de voces o no, las voces tienen que estar ordenadas por nivel y número
        /// </summary>
        /// <param name="listadoDeVoces"></param>


        private int ProcesarSumarioParaDocumento(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, string nombreDocumento, XElement sumariosElement, int i, tJurisSumarioCaratula tjurissumarioCaratula)
        {
            MigraDocLog migraDocLogEntry = new MigraDocLog();
            migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
            migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tJurisSumario;
            migraDocLogEntry.Excepcion = false;
            migraDocLogEntry.Mensaje = string.Empty;

            try
            {
                if (!tjurissumarioCaratula.tJurisSumario.IdIdentLexis.HasValue)
                {
                    string message = string.Format("La caratula del sumario no tiene un fallo asociado activo archfisico {0}, idjjsumario {1}, idcaratula {2}", tjurissumarioCaratula.ArchTCompleto, tjurissumarioCaratula.IdJJSumario, tjurissumarioCaratula.IdCaratula);
                    LogStatusMessage(message, MigracionLogStatus.Warning);
                    migraDocLogEntry.Mensaje = message;
                }
                else
                {
                    XElement sumarioElement = new XElement("sumario", new XAttribute("pos", i));
                    sumariosElement.Add(sumarioElement);

                    Guid sumarioGuidSAE = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tJurisSumario, tjurissumarioCaratula.IdJJSumario);
                    sumarioElement.Add(new XElement("guid", sumarioGuidSAE.ToString()));
                    //Se informan los últimos términos, que no son parte del árbol de voces en <subtitulo> del sumario 
                    //            (concatenados con guión medio, tal como se ven en el OnLine)
                    migraDocLogEntry.GuidSae = sumarioGuidSAE;
                    migraDocLogEntry.ApId = tjurissumarioCaratula.IdJJSumario.ToString();
                    XElement subtituloElement = new XElement("subtitulo");
                    sumarioElement.Add(subtituloElement);

                    XElement citasElement = new XElement("citas");
                    sumarioElement.Add(citasElement);

                    XElement citaOnline = new XElement("cita", new XAttribute("tipo", CitaAp.online));
                    citasElement.Add(citaOnline);
                    string citaOnlineStr = tjurissumarioCaratula.tJurisSumario.tIdentLexis.IdentLexis;
                    citaOnline.Value = citaOnlineStr;

                    AgregarAnalisisDeCita(citasElement, tjurissumarioCaratula.tCita);

                    // Agrego la clasificacion del tagging
                    XElement nroClasificacionElement = new XElement("nro-clasificacion");
                    sumarioElement.Add(nroClasificacionElement);

                    using (TaggingEntities ctxTagging = new TaggingEntities())
                    {
                        List<int?> clasificacionesDelSumario = (from doc in ctxTagging.tDocumentos
                                                                join paq in ctxTagging.tPaquetes on doc.IdPaquete equals paq.IdPaquete
                                                                where doc.IdDocumento == citaOnlineStr
                                                                select paq.Clasificacion).ToList();

                        if (clasificacionesDelSumario.Count > 0)
                        {
                            if (clasificacionesDelSumario[0].HasValue)
                            {
                                nroClasificacionElement.Value = clasificacionesDelSumario[0].Value.ToString();
                            }
                        }
                    }

                    // Campo autor
                    XElement autorElement = new XElement("autor");
                    sumarioElement.Add(autorElement);
                    bool esSumarioOficial = true;
                    if (tjurissumarioCaratula.tJurisSumario.IdBase.HasValue)
                    {
                        int idBase = tjurissumarioCaratula.tJurisSumario.IdBase.Value;
                        if (idBase == 3)
                        {
                            autorElement.Value = "Abeledo";
                            esSumarioOficial = false;
                        }
                        else if (idBase == 4)
                        {
                            autorElement.Value = "Poder Judicial (Nacional)";
                            esSumarioOficial = true;
                        }
                        else if (idBase == 5)
                        {
                            autorElement.Value = "Poder Judicial (Provinciales)";
                            esSumarioOficial = true;
                        }
                    }

                    //Se agrega el campo <autor> en el sumario para indicar si es un sumario de abeledo o es un sumario oficial, valores posibles a informar:
                    //        Abeledo (para los sumarios de Abeledo)
                    //        Poder Judicial (para los sumarios oficiales)					
                    //        Adrián/MAC: Validar que si autor = Abeledo, las voces se informen en <voces> <unificado>
                    //                                si autor = Poder Judicial, las voces se inforan en <voces> <oficiales>

                    //3	AR_JA001	Jurisprudencia: LexisNexis -sumarios-
                    //4	AR_JA002	Jurisprudencia: bases de los tribunales nacionales -sumarios-
                    //5	AR_JA003	Jurisprudencia: bases de los tribunales provinciales -sumarios-
                    //6	AR_JA004	Jurisprudencia: fallos a texto completo


                    StringBuilder cuerpoSumario = new StringBuilder();
                    cuerpoSumario.Append(tjurissumarioCaratula.tJurisSumario.Cuerpo);
                    if (!string.IsNullOrEmpty(tjurissumarioCaratula.tJurisSumario.Anexo))
                    {
                        cuerpoSumario.Append("<anexo>");
                        cuerpoSumario.Append(tjurissumarioCaratula.tJurisSumario.Anexo);
                        cuerpoSumario.Append("</anexo>");
                    }

                    sumarioElement.Add(new XElement("texto", new XCData(ProcesarCuerpo(ctxPeOnline, sumarioGuidSAE, tjurissumarioCaratula.tJurisSumario.IdJJSumario, cuerpoSumario.ToString()))));

                    // Obtener las voces
                    XElement sumariovocesElement = new XElement("voces");
                    sumarioElement.Add(sumariovocesElement);

                    sumariovocesElement.Add(new XElement("nomenclador")); // No se informa
                    sumariovocesElement.Add(new XElement("referencia")); // No se informa

                    XElement unificadoElement = new XElement("unificado");
                    sumariovocesElement.Add(unificadoElement); // Dentro de unificado informo las voces

                    XElement oficialesElement = new XElement("oficiales");
                    sumariovocesElement.Add(oficialesElement);

                    List<MigraVoz> vocesFiltradasPorArbolDeVoces = (from jft in tjurissumarioCaratula.tJurisSumario.tJurisSumarioTaxonomia
                                                                    orderby jft.nivel, jft.Nro
                                                                    select new MigraVoz
                                                                    {
                                                                        Nombre = HtmlDecode(jft.tTaxonomia.Nombre),
                                                                        IdTaxonomia = jft.IdTaxonomia,
                                                                        Nivel = jft.nivel,
                                                                        Numero = jft.Nro
                                                                    }).ToList();

                    vocesFiltradasPorArbolDeVoces = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVoces);

                    // para cada voz 
                    StringBuilder vozBuilder = new StringBuilder();
                    string vosSeparador = string.Empty;
                    foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                    {
                        XElement vozElement = new XElement("voz");
                        vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                        vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                        vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                        vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                        vozElement.Value = migraVoz.Nombre;

                        // Cargo las voces en el oficial o en el unificado según si es o no un sumario oficial
                        if (!esSumarioOficial)
                        {
                            if (migraVoz.EsVozDelArbolDeVoces)
                            {
                                unificadoElement.Add(vozElement);
                            }
                        }
                        else
                        {
                            oficialesElement.Add(vozElement);
                        }

                        if (!migraVoz.EsVozDelArbolDeVoces)
                        {
                            vozBuilder.Append(vosSeparador);
                            vosSeparador = " - ";
                            vozBuilder.Append(migraVoz.Nombre);
                        }
                    }

                    subtituloElement.Value = vozBuilder.ToString(); // asigno un renglon de voces separados por guion                

                    sumarioElement.Add(new XElement("corte-suprema")); // No se informa
                    sumarioElement.Add(new XElement("tribunales-sup-pcia")); // No se informa
                    sumarioElement.Add(new XElement("en-igual-sentido")); // No se informa
                    sumarioElement.Add(new XElement("en-sentido-contrario")); // No se informa
                    sumarioElement.Add(new XElement("ver-tambien")); // No se informa
                    sumarioElement.Add(new XElement("plenarios")); // No se informa
                    sumarioElement.Add(new XElement("doctrina")); // No se informa
                }
            }
            catch (Exception ex)
            {
                migraDocLogEntry.Excepcion = true;
                string message = GetExceptionMessage(ex);
                string stack = GetExceptionStackTrace(ex);
                migraDocLogEntry.Mensaje = migraDocLogEntry.Mensaje + message + stack;
                throw;
            }
            finally
            {
                ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                ctxPeOnline.SaveChanges();
            }

            return i;
        }

        /// <summary>
        /// Proceso los sumarios que no tienen texto completo
        /// </summary>
        /// <param name="ctxPeOnline"></param>
        /// <param name="idSumario"></param>
        private void GenerarXMLSumarioSinTexto(int idSumario)
        {
            string nombreDocumento = idSumario.ToString() + ".xml";
            MigraDocLog migraDocLogEntry = new MigraDocLog();
            migraDocLogEntry.NombreArchivoGenerado = nombreDocumento;
            migraDocLogEntry.ApNombreTabla = IdentityTranslationManager.tJurisSumario;
            migraDocLogEntry.Excepcion = false;
            migraDocLogEntry.Mensaje = string.Empty;

            using (PE_ONLINE_PRODUCCIONEntities ctxPeOnline = new PE_ONLINE_PRODUCCIONEntities())
            {
                try
                {
                    tJurisSumario jurisSumario = ctxPeOnline.tJurisSumario.Where(f => f.IdJJSumario == idSumario).SingleOrDefault();

                    if (jurisSumario == null)
                    {
                        LogStatusMessage("No se encontró el sumario", MigracionLogStatus.Information);
                        migraDocLogEntry.Mensaje = "No se encontró el sumario";
                        return;
                    }

                    tJurisSumarioCaratula jurisSumarioCaratula = jurisSumario.tJurisSumarioCaratula.OrderBy(s => s.IdCaratula).First();

                    if (ctxPeOnline.tJurisFallo.Where(jf => jf.ArchFisico == jurisSumarioCaratula.ArchTCompleto && jf.IdIdentLexis.HasValue).Count() > 0)
                    {
                        string message = string.Format("El sumario tiene un texto completo y no se generará un archivo con este método. Id sumario {0}, ArchTCompleto {1}", jurisSumario.IdJJSumario, jurisSumarioCaratula.ArchTCompleto);
                        LogStatusMessage(message, MigracionLogStatus.Warning);
                        migraDocLogEntry.Mensaje = message;
                        return;
                    }

                    List<tJurisSumarioCaratula> sumarioCaratulaList = new List<tJurisSumarioCaratula>();
                    // TODO: Si el sumario tiene texto completo, entonces lo proceso como un texto completo
                    // Llamar a generrarXMLTExtoCompleto y ver si ya lo procese de no procesarlo


                    bool procesar = true;
                    // En realidad un sumario, puede ser un grupo, hago ese análisis
                    JurisGrupoSumario grupo = (from gs in ctxPeOnline.JurisGrupoSumario
                                               join gsd in ctxPeOnline.JurisGrupoSumarioDetalle on gs.Id equals gsd.JurisGrupoSumarioId
                                               where gsd.IdJJSumario == idSumario
                                               select gs).FirstOrDefault();
                    // si no hay un grupo
                    if (grupo == null)
                    {
                        grupo = new JurisGrupoSumario();
                        grupo.Procesado = false;

                        // analizo si realmente es un grupo

                        sumarioCaratulaList.AddRange((from jsc in ctxPeOnline.tJurisSumarioCaratula
                                                      where (jsc.IdTribunal == jurisSumarioCaratula.IdTribunal || (!jsc.IdTribunal.HasValue && !jurisSumarioCaratula.IdTribunal.HasValue))
                                                      && (jsc.IdSala == jurisSumarioCaratula.IdSala || (!jsc.IdSala.HasValue && !jurisSumarioCaratula.IdSala.HasValue))
                                                      && (jsc.Fecha == jurisSumarioCaratula.Fecha || (!jsc.Fecha.HasValue && !jurisSumarioCaratula.Fecha.HasValue))
                                                      && (jsc.Partes == jurisSumarioCaratula.Partes)
                                                      && jsc.IdCaratula == 1
                                                      select jsc).ToList());

                        // genero el grupo
                        if (sumarioCaratulaList.Count > 1)
                        {
                            // para generar el grupo, tengo que elegir solo los de carátula menor,
                            // o sea, agrupo por número idjjsumario y elijo la carátula menor

                            // TODO:

                            ctxPeOnline.JurisGrupoSumario.AddObject(grupo);

                            grupo.TribunalId = jurisSumarioCaratula.IdTribunal;
                            grupo.SalaId = jurisSumarioCaratula.IdSala;
                            grupo.Fecha = jurisSumarioCaratula.Fecha;
                            grupo.Partes = jurisSumarioCaratula.Partes;

                            foreach (tJurisSumarioCaratula IdJJSumarioCaratula in sumarioCaratulaList)
                            {
                                // amerita crear un grupo
                                grupo.JurisGrupoSumarioDetalle.Add(new JurisGrupoSumarioDetalle()
                                {
                                    IdJJSumario = IdJJSumarioCaratula.IdJJSumario
                                });
                            }

                            ctxPeOnline.SaveChanges(); // grabo la lista de grupos
                        }
                        else if (sumarioCaratulaList.Count == 0)
                        {
                            // no genero el grupo porque es uno solo
                            sumarioCaratulaList.Add(jurisSumarioCaratula); // agrego el parametro
                        }
                    }
                    else
                    {
                        // si ya existía el grupo cargo la lista de detalles de todos los sumarios del grupo
                        foreach (JurisGrupoSumarioDetalle grupoDetalle in grupo.JurisGrupoSumarioDetalle)
                        {
                            sumarioCaratulaList.Add(ctxPeOnline.tJurisSumarioCaratula.Where(c => c.IdJJSumario == grupoDetalle.IdJJSumario).First());
                        }
                    }


                    // hay un grupo, me fijo que no esté procesado
                    procesar = !grupo.Procesado;

                    if (procesar)
                    {

                        XDocument sumarioDocument = new XDocument();

                        XElement documentoElement = new XElement("documento");
                        sumarioDocument.Add(documentoElement);
                        XElement metaDocumentoElement = new XElement("meta-documento");
                        documentoElement.Add(metaDocumentoElement);
                        XElement falloGuidElement = new XElement("guid");
                        metaDocumentoElement.Add(falloGuidElement);
                        Guid sumarioGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tJurisSumario, idSumario);
                        falloGuidElement.Value = sumarioGuid.ToString();
                        migraDocLogEntry.GuidSae = sumarioGuid;
                        migraDocLogEntry.ApId = idSumario.ToString();
                        metaDocumentoElement.Add(new XElement("iddoc"));
                        XElement citaElement = new XElement("cita");
                        metaDocumentoElement.Add(citaElement);
                        citaElement.Value = jurisSumario.tIdentLexis.IdentLexis;
                        XElement novusElement = new XElement("novus", new XElement("id"), new XElement("accion", IdTranslationManager.GetDocumentoEstadoEnviarNovus(jurisSumario.IdDocumentoEstado)), new XElement("fecha-de-modificacion", "T"));
                        metaDocumentoElement.Add(novusElement);

                        XElement fechaDeCarga = new XElement("fecha-carga");
                        metaDocumentoElement.Add(fechaDeCarga);
                        fechaDeCarga.Value = jurisSumario.FechaAlta.ToStringSAE();

                        metaDocumentoElement.Add(new XElement("fecha-ultima-modificacion", DateTime.Now.ToStringSAE()));
                        metaDocumentoElement.Add(new XElement("estado-texto", StrEstadoSinTexto));

                        XElement tribunalElement = new XElement("tribunal");
                        metaDocumentoElement.Add(tribunalElement);



                        tTribunal ttribunal = null;
                        // TODO: el ID es un entero
                        if (jurisSumarioCaratula.IdTribunal.HasValue)
                        {
                            ttribunal = ctxPeOnline.tTribunal.Where(t => t.id_tribunal == jurisSumarioCaratula.IdTribunal.Value).Single();


                            string idTribunalCombinado = ttribunal.id_tribunal.ToString();

                            if (jurisSumarioCaratula.IdSala.HasValue)
                            {
                                var sala = ctxPeOnline.tSala.Where(s => s.id_sala == jurisSumarioCaratula.IdSala.Value).SingleOrDefault();
                                if (sala != null)
                                {
                                    idTribunalCombinado += "S" + HtmlDecode(sala.nombre);
                                }
                            }

                            tribunalElement.Add(new XAttribute("descripcion", HtmlDecode(ttribunal.nombre)), new XAttribute("idoriginal", idTribunalCombinado));

                            tribunalElement.Value = IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTribunal, idTribunalCombinado);
                        }

                        metaDocumentoElement.Add(new XElement("nota-interna", StrNotaInterna));

                        // metaDocumentoElement.Add(new XElement("tribunal-procedencia"));

                        //<nro-sentencia nro-sentencia="" nro-expediente="">
                        string nroSentencia = jurisSumario.NroSentencia ?? string.Empty;
                        string nroExpediente = jurisSumario.NroExpediente ?? string.Empty;
                        metaDocumentoElement.Add(new XElement("nro-sentencia", nroSentencia));
                        metaDocumentoElement.Add(new XElement("nro-expediente", nroExpediente));

                        metaDocumentoElement.Add(new XElement("fecha-sentencia", jurisSumarioCaratula.Fecha.ToStringSAE()));

                        using (TaggingEntities ctxTagging = new TaggingEntities())
                        {
                            tFallos falloTagging = ctxTagging.tFallos.Where(t => t.IdDocumento == jurisSumario.tIdentLexis.IdentLexis).SingleOrDefault();

                            if (falloTagging != null)
                            {
                                metaDocumentoElement.Add(new XElement("parte-actora"));
                                metaDocumentoElement.Add(new XElement("parte-actora-pub", falloTagging.Actor));
                                metaDocumentoElement.Add(new XElement("parte-demandada"));
                                metaDocumentoElement.Add(new XElement("parte-demandada-pub", falloTagging.Demandado));
                                metaDocumentoElement.Add(new XElement("partes", HtmlDecode(jurisSumarioCaratula.Partes)));
                                metaDocumentoElement.Add(new XElement("objeto", falloTagging.Objeto));
                            }
                            else
                            {
                                metaDocumentoElement.Add(new XElement("parte-actora"));
                                metaDocumentoElement.Add(new XElement("parte-actora-pub"));
                                metaDocumentoElement.Add(new XElement("parte-demandada"));
                                metaDocumentoElement.Add(new XElement("parte-demandada-pub"));
                                metaDocumentoElement.Add(new XElement("partes", HtmlDecode(jurisSumarioCaratula.Partes)));
                                metaDocumentoElement.Add(new XElement("objeto"));
                            }
                        }

                        tSentencia tsentencia = ctxPeOnline.tSentencia.Where(s => s.IdSentencia == jurisSumario.IdTipoSentencia).SingleOrDefault();
                        XElement tipoSentenciaElement = new XElement("tipo-sentencia");
                        metaDocumentoElement.Add(tipoSentenciaElement);
                        if (tsentencia != null)
                        {
                            tipoSentenciaElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tSentencia, HtmlDecode(tsentencia.Descripcion)).ToString();
                        }

                        // TODO: revisar con regular expressión las citas : Cambiar las citas diferenciando entre fallos de corte y apariciones
                        XElement citaFalloCorteElement = new XElement("cita-fallo-corte");
                        metaDocumentoElement.Add(citaFalloCorteElement);

                        XElement aparicionesElement = new XElement("apariciones");

                        // No informar
                        metaDocumentoElement.Add(new XElement("nro-plenario"));
                        metaDocumentoElement.Add(new XElement("rol"));
                        XElement tituloElement = new XElement("titulo");
                        metaDocumentoElement.Add(tituloElement);

                        // Ministros
                        XElement ministrosElement = new XElement("ministros");
                        bool sinDisidenciaMnistro = false;
                        metaDocumentoElement.Add(ministrosElement);
                        foreach (var jurisMinistro in jurisSumario.tJurisSumarioCaratulaMinistro)
                        {
                            tMinistro magistrado = ctxPeOnline.tMinistro.Where(m => m.IdMinistro == jurisMinistro.IdMinistro).Single();
                            if (magistrado.Nombre == "SIN DISIDENCIA" || jurisMinistro.TipoVoto == 6)
                            {
                                sinDisidenciaMnistro = true;
                            }
                            else
                            {
                                XElement ministroElement = new XElement("ministro");

                                ministroElement.Add(new XAttribute("nombre", HtmlDecode(magistrado.Nombre)));
                                ministroElement.Add(new XAttribute("orden", jurisMinistro.Orden));
                                ministroElement.Add(new XAttribute("tipovoto", IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoVoto, jurisMinistro.TipoVoto)));
                                ministroElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tMinistro, magistrado.IdMinistro).ToString();
                                ministrosElement.Add(ministroElement);
                            }
                        }

                        metaDocumentoElement.Add(new XElement("sin-disidencia", sinDisidenciaMnistro ? "SI" : "NO"));

                        metaDocumentoElement.Add(new XElement("redactores")); // Chile no informar
                        metaDocumentoElement.Add(new XElement("abogados-integrantes"));

                        metaDocumentoElement.Add(aparicionesElement);

                        //metaDocumentoElement.Add(new XElement("publicacion"));
                        metaDocumentoElement.Add(new XElement("asignaciones"));

                        XElement collectionsSetElement = new XElement("collection-sets");
                        metaDocumentoElement.Add(collectionsSetElement);
                        // Se agregan los productos
                        foreach (tProducto tproducto in jurisSumario.tProducto1)
                        {
                            List<Guid> guidForProductoList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tProducto, tproducto.id_producto);

                            foreach (Guid guidForProducto in guidForProductoList)
                            {
                                XElement collectionSetElement = new XElement("collection-set");
                                collectionsSetElement.Add(collectionSetElement);
                                collectionSetElement.Value = guidForProducto.ToString();
                            }
                        }

                        metaDocumentoElement.Add(new XElement("productos-digitales"));

                        // TODO: solo las voces, no los terminos libres
                        XElement vocesIndizacionElement = new XElement("voces-indizacion");
                        metaDocumentoElement.Add(vocesIndizacionElement);

                        XElement vocesElement = new XElement("voces");
                        XElement vozPrincipalElement = new XElement("voz-principal");
                        vocesElement.Add(vozPrincipalElement);
                        XElement subVocesElement = new XElement("sub-voces");
                        vocesElement.Add(subVocesElement);


                        List<MigraVoz> vocesFiltradasPorArbolDeVoces = (from jft in jurisSumario.tJurisSumarioTaxonomia
                                                                        orderby jft.nivel, jft.Nro
                                                                        select new MigraVoz
                                                                        {
                                                                            Nombre = HtmlDecode(jft.tTaxonomia.Nombre),
                                                                            IdTaxonomia = jft.IdTaxonomia,
                                                                            Nivel = jft.nivel,
                                                                            Numero = jft.Nro
                                                                        }).ToList();

                        vocesFiltradasPorArbolDeVoces = FiltrarPorArbolDeVoces(vocesFiltradasPorArbolDeVoces);

                        StringBuilder tituloBuilder = new StringBuilder();
                        string separador = string.Empty;
                        foreach (MigraVoz migraVoz in vocesFiltradasPorArbolDeVoces)
                        {
                            XElement vozElement;
                            if (migraVoz.EsVozDelArbolDeVoces) //Se informan las voces que son parte del árbol como voces, en <voces-indizacion> del fallo.
                            {
                                vozElement = new XElement("voz-indizacion");
                                vozElement.Add(new XAttribute("numero", migraVoz.Numero));
                                vozElement.Add(new XAttribute("nivel", migraVoz.Nivel));
                                vozElement.Add(new XAttribute("id_taxonomia", migraVoz.IdTaxonomia));
                                vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                                vozElement.Value = migraVoz.Nombre;
                                vocesIndizacionElement.Add(vozElement);

                                vozElement = new XElement("voz");
                                vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                                vozElement.Value = migraVoz.Nombre;
                                vozPrincipalElement.Add(vozElement);
                            }
                            else
                            {
                                tituloBuilder.Append(separador);
                                separador = " " + SeparadorDeVocesChar + " ";
                                tituloBuilder.Append(migraVoz.Nombre);
                            }

                            vozElement = new XElement("voz");
                            vozElement.Add(new XAttribute("vozArbol", migraVoz.EsVozDelArbolDeVoces));
                            vozElement.Value = migraVoz.Nombre;
                            subVocesElement.Add(vozElement);
                        }

                        tituloElement.Value = tituloBuilder.ToString();

                        metaDocumentoElement.Add(vocesElement);
                        metaDocumentoElement.Add(new XElement("citas-legales"));
                        metaDocumentoElement.Add(new XElement("hechos"));
                        metaDocumentoElement.Add(new XElement("comentario-dj"));
                        metaDocumentoElement.Add(new XElement("pais", StrPais));

                        metaDocumentoElement.Add(new XElement("informacion-complementaria"));
                        metaDocumentoElement.Add(new XElement("honorarios-del-abogado"));
                        metaDocumentoElement.Add(new XElement("cuota-alimentaria"));

                        XElement integraciontribunalElement = new XElement("integracion-tribunal");
                        metaDocumentoElement.Add(integraciontribunalElement);
                        bool sinDisidencia = false;
                        foreach (var jurisMinistro in jurisSumario.tJurisSumarioCaratulaMinistro)
                        {
                            tMinistro magistrado = ctxPeOnline.tMinistro.Where(m => m.IdMinistro == jurisMinistro.IdMinistro).Single();
                            if (magistrado.Nombre == "SIN DISIDENCIA" || jurisMinistro.TipoVoto == 6)
                            {
                                sinDisidencia = true;
                            }
                            else
                            {
                                XElement magistradoElement = new XElement("magistrado");


                                magistradoElement.Add(new XAttribute("nombre", HtmlDecode(magistrado.Nombre)));
                                magistradoElement.Add(new XAttribute("orden", jurisMinistro.Orden));
                                magistradoElement.Add(new XAttribute("tipovoto", IdTranslationManager.GetStringIdForApEntity(IdentityTranslationManager.tTipoVoto, jurisMinistro.TipoVoto)));
                                magistradoElement.Value = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tMinistro, magistrado.IdMinistro).ToString();
                                integraciontribunalElement.Add(magistradoElement);
                            }
                        }

                        metaDocumentoElement.Add(new XElement("sin-disidencia", sinDisidencia ? "SI" : "NO"));

                        // TODO: buscar la doctrina relacionada (falta definir formato, nota a fallo)
                        XElement documentosRelacionadosElement = new XElement("documentos-relacionados");
                        metaDocumentoElement.Add(documentosRelacionadosElement);


                        XElement materiasElement = new XElement("materias");
                        metaDocumentoElement.Add(materiasElement);

                        var tjurisSumarioMaterias = ctxPeOnline.tJurisSumarioMateria.Where(tjfm => tjfm.idJJSumario == jurisSumario.IdJJSumario).ToList();
                        string separadorNuflo = string.Empty;
                        foreach (var tjurisSumarioMateria in tjurisSumarioMaterias)
                        {
                            tMateria materia = ctxPeOnline.tMateria.Where(m => m.id_Materia == tjurisSumarioMateria.id_Materia).Single();
                            List<Guid> guidSaeMateriaList = IdTranslationManager.GetGuidListIdForApEntity(IdentityTranslationManager.tMateria, materia.id_Materia);//GetGuidListIdForApEntity
                            foreach (Guid guidSaeMateria in guidSaeMateriaList)
                            {
                                XElement materiaElement = new XElement("materia");
                                materiaElement.Add(new XAttribute("identificador", materia.Identificador));
                                materiaElement.Add(new XAttribute("nombre", HtmlDecode(materia.Descripcion)));
                                materiaElement.Value = guidSaeMateria.ToString();
                                materiasElement.Add(materiaElement);
                            }
                        }

                        // Chile, no informar
                        metaDocumentoElement.Add(new XElement("estado-procesal"));
                        metaDocumentoElement.Add(new XElement("tipo-recurso"));
                        metaDocumentoElement.Add(new XElement("tipo-resultado"));


                        XElement contenidoDocumentoElement = new XElement("cont-documento");
                        documentoElement.Add(contenidoDocumentoElement);


                        XElement textoSentenciaElement = new XElement("texto-sentencia");
                        contenidoDocumentoElement.Add(textoSentenciaElement);

                        XElement sumariosElement = new XElement("sumarios");
                        contenidoDocumentoElement.Add(sumariosElement);

                        int i = 0;
                        foreach (tJurisSumarioCaratula tjurissumarioCaratula in sumarioCaratulaList)
                        {
                            ProcesarSumarioParaDocumento(ctxPeOnline, nombreDocumento, sumariosElement, i, tjurissumarioCaratula);
                            i++;
                        }

                        string path = Path.Combine(this.OutputPath, "Sumarios");
                        if (!Directory.Exists(path))
                        {
                            Directory.CreateDirectory(path);
                        }

                        sumarioDocument.Save(Path.Combine(path, nombreDocumento));

                        if (grupo.Id != 0)
                        {
                            grupo.Procesado = true;
                            ctxPeOnline.SaveChanges();
                        }
                    }
                }
                catch (Exception ex)
                {
                    migraDocLogEntry.Excepcion = true;
                    string message = GetExceptionMessage(ex);
                    string stack = GetExceptionStackTrace(ex);
                    migraDocLogEntry.Mensaje = migraDocLogEntry.Mensaje + message + stack;
                    throw;
                }
                finally
                {
                    ctxPeOnline.MigraDocLog.AddObject(migraDocLogEntry);
                    ctxPeOnline.SaveChanges();
                }
            }
        }
    }
}
